// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.core.components;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import org.dengues.commons.i18n.MessagesCore;
import org.dengues.commons.ui.swt.colorstyledtext.EModeLanguage;
import org.dengues.commons.utils.DenguesTextUtil;
import org.dengues.core.DenguesCorePlugin;
import org.dengues.core.ExceptionOperation;
import org.dengues.core.IDesignerCoreService;
import org.dengues.core.components.EJETCodePart;
import org.dengues.core.components.EMFConnection;
import org.dengues.core.components.ENodeParameterName;
import org.dengues.core.components.IComponentsFactory;
import org.dengues.core.components.IXMLComponent;
import org.dengues.core.components.NodePropertyParameter;
import org.dengues.core.metadata.MetadataColumn;
import org.dengues.core.metadata.MetadataTable;
import org.dengues.core.module.EClasspathVariables;
import org.dengues.core.module.EMFModule;
import org.dengues.core.process.ICompNode;
import org.dengues.core.property.EParameterFieldCategory;
import org.dengues.core.property.EPropertyCategory;
import org.dengues.model.component.COLMUNType;
import org.dengues.model.component.COMPONENTType;
import org.dengues.model.component.CONNECTIONType;
import org.dengues.model.component.DocumentRoot;
import org.dengues.model.component.IMPORTSType;
import org.dengues.model.component.IMPORTType;
import org.dengues.model.component.ITEMSType;
import org.dengues.model.component.ITEMType;
import org.dengues.model.component.PARAMETERType;
import org.dengues.model.component.util.ComponentResourceFactoryImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.resource.ImageDescriptor;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class EmfXMLComponent implements IXMLComponent {

    private ImageDescriptor icon32;

    private ImageDescriptor icon24;

    private ImageDescriptor icon16;

    private final File xmlMainFile;

    private final String pathSource;

    private boolean isLoaded = false;

    private ResourceBundle resourceBundle;

    private List<EJETCodePart> codePartList;

    private COMPONENTType compType;

    private String pluginId = IComponentsFactory.COMPONENTS_LOCATION;

    /**
     * Qiang.Zhang.Adolf@gmail.com EmfXMLComponent constructor comment.
     * 
     * @param xmlMainFile
     * @param pathSource
     */
    public EmfXMLComponent(File xmlMainFile, String pathSource) {
        this.xmlMainFile = xmlMainFile;
        this.pathSource = pathSource;
        load();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "load".
     */
    private void load() {
        if (!isLoaded) {
            try {
                ResourceSet resourceSet = new ResourceSetImpl();
                ComponentResourceFactoryImpl compFact;
                compFact = new ComponentResourceFactoryImpl();
                URI createURI = URI.createURI(xmlMainFile.toURI().toString());
                compFact.createResource(createURI);
                resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
                        Resource.Factory.Registry.DEFAULT_EXTENSION, compFact);
                Resource res = resourceSet.getResource(createURI, true);
                DocumentRoot xmlDoc;
                xmlDoc = (DocumentRoot) res.getContents().get(0);
                compType = (COMPONENTType) xmlDoc.eContents().get(0);
                checkAvailableCodeParts();
                isLoaded = true;
            } catch (Exception e) {
                ExceptionOperation.operate(e);
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "checkAvailableCodeParts".
     */
    private void checkAvailableCodeParts() {
        codePartList = new ArrayList<EJETCodePart>();
        File dirFile = new File(xmlMainFile.getParent());
        final String extension = "." + EModeLanguage.JAVA.getLanguageMode() + "jet"; //$NON-NLS-1$ //$NON-NLS-2$
        FilenameFilter fileNameFilter = new FilenameFilter() {

            public boolean accept(File dir, String name) {
                return name.endsWith(extension);
            }
        };

        String[] jetFiles = dirFile.list(fileNameFilter);

        for (int i = 0; i < jetFiles.length; i++) {
            String name = jetFiles[i];
            name = jetFiles[i].replace(getName() + "_", ""); //$NON-NLS-1$ //$NON-NLS-2$
            name = name.replace(extension, ""); //$NON-NLS-1$
            EJETCodePart part = EJETCodePart.getCodePartByName(name);
            if (part != null) {
                codePartList.add(part);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IComponent#getName()
     */
    public String getName() {
        return xmlMainFile.getParentFile().getName();
    }

    public void setResourceBundle(ResourceBundle resourceBundle) {
        this.resourceBundle = resourceBundle;
    }

    public ResourceBundle getResourceBundle() {
        return this.resourceBundle;
    }

    public ImageDescriptor getIcon16() {
        return this.icon16;
    }

    public void setIcon16(ImageDescriptor icon16) {
        this.icon16 = icon16;
    }

    public ImageDescriptor getIcon24() {
        return this.icon24;
    }

    public void setIcon24(ImageDescriptor icon24) {
        this.icon24 = icon24;
    }

    public ImageDescriptor getIcon32() {
        return this.icon32;
    }

    public void setIcon32(ImageDescriptor icon32) {
        this.icon32 = icon32;
    }

    public boolean isLoaded() {
        return this.isLoaded;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IComponent#getDisplayName()
     */
    public String getDisplayName() {
        return getTranslatedName();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IComponent#getLongName()
     */
    public String getLongName() {
        return getTranslatedValue(PROP_LONG_NAME);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IComponent#getAvailableCodeParts()
     */
    public List<EJETCodePart> getAvailableCodeParts() {
        return this.codePartList;
    }

    public String getPathSource() {
        return this.pathSource;
    }

    public String getVersion() {
        return this.compType.getHEADER().getVERSION();
    }

    private String getTranslatedValue(final String nameValue) {
        String returnValue = nameValue;
        returnValue = MessagesCore.getString(nameValue, getResourceBundle());
        return returnValue;
    }

    public List<NodePropertyParameter> createNodeParameters(ICompNode node) {
        List<NodePropertyParameter> params = new ArrayList<NodePropertyParameter>();
        addMainParameters(params, node);
        addPropertyParameters(params, node);
        return params;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addMainParameters".
     * 
     * @param listParam
     * @param node
     */
    private void addMainParameters(List<NodePropertyParameter> listParam, ICompNode node) {
        NodePropertyParameter param;
        param = new NodePropertyParameter(node);
        param.setName(ENodeParameterName.UNIQUE_NAME.getName());
        param.setValue(""); //$NON-NLS-1$
        param.setDisplayName(ENodeParameterName.UNIQUE_NAME.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(1);
        listParam.add(param);

        param = new NodePropertyParameter(node);
        param.setName(ENodeParameterName.COMPONENT_NAME.getName());
        param.setValue(getName()); //$NON-NLS-1$
        param.setDisplayName(ENodeParameterName.COMPONENT_NAME.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(1);
        listParam.add(param);

        param = new NodePropertyParameter(node);
        param.setName(ENodeParameterName.CATEGORY.getName());
        param.setValue(getCategory()); //$NON-NLS-1$
        param.setDisplayName(ENodeParameterName.CATEGORY.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(2);
        listParam.add(param);

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addPropertyParameters".
     * 
     * @param params
     * @param node
     */
    private void addPropertyParameters(List<NodePropertyParameter> params, ICompNode node) {
        EList<PARAMETERType> parameters = compType.getPARAMETERS().getPARAMETER();
        for (PARAMETERType type : parameters) {
            NodePropertyParameter parameter = new NodePropertyParameter(node);
            EParameterFieldCategory category = EParameterFieldCategory.getCategoryFromField(type.getFIELD());
            parameter.setField(type.getFIELD());
            parameter.setFieldCategory(category);
            parameter.setName(type.getNAME());
            parameter.setDisplayName(getTranslatedValue(type.getNAME() + "." + PROP_NAME)); //$NON-NLS-1$
            parameter.setNbRow(type.getROWNUM());
            parameter.setPropertyCategory(EPropertyCategory.PROPERTY);
            parameter.setShow(type.isIFSHOW());
            parameter.setReadOnly(type.isIFREADONLY());
            parameter.setRequired(type.isIFREQUIRED());
            parameter.setRepositoryValue(type.getREPOSITORYVALUE());
            parameter.setContext(type.getCONTEXT());
            parameter.setNbLines(type.getNBLINES());
            parameter.setBaseSchema(type.isBASESHEMA());
            ITEMSType items = type.getITEMS();
            switch (category) {
            case TABLE:
                parameter.setValue(new ArrayList<Map<String, Object>>());
                break;
            case CHECK:
                parameter.setValue(new Boolean("true".equals(type.getDEFAULT()))); //$NON-NLS-1$
                break;
            default:
                parameter.setValue(DenguesTextUtil.getNotNullString(type.getDEFAULT()));
                break;
            }
            if (items != null) {
                addItemsPropertyParameters(parameter, items, category, node);
            }
            EList<COLMUNType> colmun = type.getCOLMUN();
            if (colmun != null && !colmun.isEmpty() && EParameterFieldCategory.METADATA == category) {
                node.getMetadataList().clear();
                MetadataTable metadataTable = new MetadataTable();
                metadataTable.setTableName(type.getNAME());
                for (COLMUNType type2 : colmun) {
                    MetadataColumn column = new MetadataColumn();
                    column.setColumnName(type2.getNAME());
                    column.setComment(type2.getCOMMENT());
                    column.setDefaut(type2.getDEFAULT());
                    column.setKey(type2.isKEY());
                    column.setLength(type2.getLENGTH());
                    column.setMetadataTable(metadataTable);
                    column.setNullable(type2.isNULLABLE());
                    column.setPattern(type2.getPATTERN());
                    column.setPrecision(type2.getPRECISION());
                    column.setType(type2.getTYPE());
                    metadataTable.getColumns().add(column);
                }
                node.getMetadataList().add(metadataTable);
            }
            params.add(parameter);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addItemsPropertyParameters".
     * 
     * @param parameter
     * @param type
     * @param displayItems
     * @param items
     * @param category
     * @param node
     */
    private void addItemsPropertyParameters(NodePropertyParameter parameter, ITEMSType items, EParameterFieldCategory category,
            ICompNode node) {
        NodePropertyParameter newParam;
        int num = items.getITEM().size();
        if (parameter.isBaseSchema()) {
            num++;
        }
        String[] displayNameItems = new String[num];
        String[] itemNames = new String[num];
        Object[] itemValues = new Object[num];
        List<ITEMType> its = items.getITEM();
        String defalut = items.getDEFALUT();
        if (defalut != null && EParameterFieldCategory.TABLE != category) {
            parameter.setValue(defalut);
        }

        int i = 0;
        if (parameter.isBaseSchema()) {
            displayNameItems[i] = getTranslatedValue(parameter.getName() + "." + items.getNAME() + "." + COLUMN_SCHEMA); //$NON-NLS-1$ //$NON-NLS-2$
            itemNames[i] = COLUMN_SCHEMA;
            if (EParameterFieldCategory.TABLE != category) {
                itemValues[i] = COLUMN_SCHEMA;
            } else {
                newParam = new NodePropertyParameter(node);
                newParam.setName(COLUMN_SCHEMA);
                newParam.setDisplayName(""); //$NON-NLS-1$
                newParam.setFieldCategory(EParameterFieldCategory.TEXT);
                newParam.setValue(""); //$NON-NLS-1$
                newParam.setField(EParameterFieldCategory.TEXT.getName());
                itemValues[i] = newParam;
            }
            i++;
        }
        for (; i < num; i++) {
            int j = i;
            if (parameter.isBaseSchema()) {
                j = i - 1;
            }
            ITEMType item = its.get(j);
            displayNameItems[i] = getTranslatedValue(parameter.getName() + "." + items.getNAME() + "." + item.getNAME()); //$NON-NLS-1$ //$NON-NLS-2$
            itemNames[i] = item.getNAME();
            if (EParameterFieldCategory.TABLE != category) {
                itemValues[i] = item.getVALUE();
            } else {
                EParameterFieldCategory cc = EParameterFieldCategory.getCategoryFromField(item.getFIELD());
                newParam = new NodePropertyParameter(node);
                newParam.setName(item.getNAME());
                newParam.setDisplayName(""); //$NON-NLS-1$
                newParam.setField(item.getFIELD());
                newParam.setFieldCategory(cc);
                switch (cc) {
                case COMBO:
                    addItemsPropertyParameters(newParam, item.getITEMS(), cc, node);
                    break;
                case CHECK:
                    newParam.setValue(new Boolean("true".equals(item.getVALUE())));
                    break;
                default:
                    newParam.setValue(item.getVALUE());
                    break;
                }
                itemValues[i] = newParam;
            }
        }
        parameter.setItemNames(itemNames);
        parameter.setItemDisplayNames(displayNameItems);
        parameter.setItemValues(itemValues);
    }

    private String getTranslatedName() {
        return getTranslatedValue(PROP_NAME);
    }

    public List<EMFConnection> createConnections() {
        List<EMFConnection> conns = new ArrayList<EMFConnection>();
        EList<CONNECTIONType> connections = compType.getCONNECTIONS().getCONNECTION();
        for (CONNECTIONType conn : connections) {
            EMFConnection connection = new EMFConnection();
            int maxoutput = conn.getMAXOUTPUT();
            int mininput = conn.getMININPUT();
            int minoutput = conn.getMINOUTPUT();
            String name = conn.getNAME();
            connection.setMaxinput(conn.getMAXINPUT());
            connection.setMaxoutput(maxoutput);
            connection.setMininput(mininput);
            connection.setMinoutput(minoutput);
            connection.setName(name);
            conns.add(connection);
        }
        return conns;
    }

    /**
     * Getter for isStart.
     * 
     * @return the isStart
     */
    public boolean isStart() {
        return compType.getHEADER().isSTARTABLE();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IXMLComponent#getCategory()
     */
    public String getCategory() {
        return getTranslatedValue(CATEGORY);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IXMLComponent#getImportModules()
     */
    public List<EMFModule> getImportModules() {
        List<EMFModule> list = new ArrayList<EMFModule>();
        IMPORTSType imports = compType.getIMPORTS();
        if (imports != null) {
            EList<IMPORTType> importList = imports.getIMPORT();
            for (IMPORTType type : importList) {
                EClasspathVariables valueOf = EClasspathVariables.getClassVarFromJar(type.getMODULE());
                EMFModule module = new EMFModule();
                module.setName(type.getNAME());
                module.setLibJar(type.getMODULE());
                if (valueOf != null) {
                    IDesignerCoreService designerCoreService = DenguesCorePlugin.getDefault().getDesignerCoreService();
                    module.setModulePath(designerCoreService.getLibPath(valueOf));
                    module.setUrl(designerCoreService.getLibURL(valueOf));
                }
                list.add(module);
            }
        }
        return list;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IXMLComponent#getExternalPlugin()
     */
    public String getExternalPlugin() {
        return compType.getHEADER().getEXTENSION();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.components.IXMLComponent#isExternalNode()
     */
    public boolean isExternalNode() {
        return getExternalPlugin() != null && !"".equals(getExternalPlugin());
    }

    /**
     * Getter for pluginId.
     * 
     * @return the pluginId
     */
    public String getPluginId() {
        return this.pluginId;
    }

    /**
     * Sets the pluginId.
     * 
     * @param pluginId the pluginId to set
     */
    public void setPluginId(String pluginId) {
        this.pluginId = pluginId;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return getPluginId() + ":" + getPathSource() + ":" + getName();
    }

}
